#!/bin/sh

# Copyright (c) 2009-2010 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# This script contains some functions useful to build
# Valgrind and ThreadSanitizer for use with chromium

THISDIR=$(dirname "${0}")
THISDIR=$(cd "${THISDIR}" && /bin/pwd)
VG_SRC_DIR=/tmp/valgrind-src

system_is_snow_leopard() {
  uname -r | grep 10\.[0-9]\.[0-9] >/dev/null
}

system_is_lion() {
  uname -r | grep 11\.[0-9]\.[0-9] >/dev/null
}

system_is_mountain_lion() {
  uname -r | grep 12\.[0-9]\.[0-9] >/dev/null
}

checkout_and_patch_valgrind_variant() {
  # $1 = Valgrind-variant revision
  # $2 = source dir
  # Checkout Valgrind, apply our patches to Valgrind.
  # The source will be put in $VG_SRC_DIR/valgrind-source
  mkdir -p "$VG_SRC_DIR"
  cd "$VG_SRC_DIR"
  VG_REV="$1"
  SOURCE_DIR="$2"
  SVN_URI="http://valgrind-variant.googlecode.com/svn/trunk"

  test -d "$SOURCE_DIR" && rm -rf "$SOURCE_DIR"
  mkdir "$SOURCE_DIR"

  # Check out latest version that following patches known to apply against
  svn co -r "$VG_REV" "$SVN_URI" "$SOURCE_DIR"
  cd $SOURCE_DIR/valgrind
}

build_valgrind() {
  # Build Valgrind from sources in the current directory.
  # $1 = output directory name for binaries
  # $2 = flags to pass to configure
  # {{{1
  OUTPUT_DIR="$BINARIES_DIR/$1"
  CONFIGURE_FLAGS=$2

  PREV_DIR=`pwd`

  # Wipe out all Makefiles which could be left by the previous installation.
  make distclean || true

  sh autogen.sh || autoreconf -fvi
  if test -L install-sh
  then
    # replace symlink with actual contents!
    cp install-sh install-sh.new
    mv -f install-sh.new install-sh
    chmod +x install-sh
  fi

  ./configure $CONFIGURE_FLAGS --prefix="${OUTPUT_DIR}"
  make -j8

  # Test if Valgrind binary works on a simple program {{{2
cat > simpletest.c <<EOF
#include <stdio.h>
int main(void) {
  printf("OK\n");
  return 0;
}
EOF
  if echo "$CONFIGURE_FLAGS" | grep "\-\-enable\-only32bit";
  then
    gcc -m32 simpletest.c -o simpletest
  else
    gcc simpletest.c -o simpletest
  fi

  if ! ./vg-in-place ./simpletest
  then
    echo built valgrind fails smoke test
    exit 1
  fi
  # }}}

  test -d "${OVERRIDE_LD_DIR}" && rm -rf "${OVERRIDE_LD_DIR}"

  # Finally install valgrind to $OUTPUT_DIR.
  make -j8 install

  if [ "$CONFIGURE_FLAGS" == "" ] ; then
    rm -rf "$BINARIES_DIR/local"
    ln -s "$OUTPUT_DIR" "$BINARIES_DIR/local"
  fi

  maybe_build_gdb_for_mac "$OUTPUT_DIR"

  # Delete un-needed stuff from the $OUTPUT_DIR
  # TODO(timurrrr): probably, we should just don't build the unused tools
  cd "$OUTPUT_DIR"
  rm -rf include
  rm -rf lib/pkgconfig lib/*.a
  rm bin/*cg_* bin/callgrind*
  cd lib/valgrind
  rm -rf *.a \
    *drd* \
    *exp-* \
    *none* \
    *lackey* \
    *massif* \
    *helgrind* \
    *callgrind* \
    *cachegrind*

  # Strip all binaries except "vgpreload" (we do need their symbols).
  strip `ls -1 | grep "memcheck" | grep -v "dSYM" | grep -v "vgpreload"`

  # Some tools may define some post-build steps, e.g. ThreadSanitzer.
  if [ "$POST_BUILD_HOOK_DEFINED" != "" ]
  then
    post_build_hook $1 $2
  fi

  # We're done
  cd "$PREV_DIR"
  # }}}
}

maybe_build_gdb_for_mac() {
  # {{{1
  # MacOSX before Snow Leopoard needs newer gdb to be able to handle -O1 chrome
  # Kludgily download and unpack the sources in a subdirectory,
  # then install into $1.
  # This is SLOW and we want it to run only once, so we execute it only
  # if explicitly asked to do so.
  if [ "${BUILD_GDB}" = "yes" ]
  then
    curl http://www.opensource.apple.com/tarballs/gdb/gdb-1344.tar.gz | tar -xzf -
    cd gdb-1344/src
    ./configure --prefix="$1"
    # gdb makefile is not yet parallel-safe
    make
    make install
    cd ../..
  fi
  # }}}
}

build_valgrind_for_available_platforms() {
  case `uname -sm` in
    "Linux x86_64")
      # We can build both 64/32-bit and 32-bit Valgrinds
      build_valgrind "linux_x64"
      build_valgrind "linux_x86" "--enable-only32bit"
      ;;
    "Darwin i386")
      if uname -r | grep 9\.[0-9]\.[0-9] >/dev/null
      then
        build_valgrind "mac"
      elif system_is_snow_leopard
      then
        build_valgrind "mac_10.6" "--build=amd64-darwin"
      elif system_is_lion
      then
        build_valgrind "mac_10.7" "--build=amd64-darwin"
      elif system_is_mountain_lion
      then
        build_valgrind "mac_10.8"
      else
        echo "You have Darwin kernel different from 9.X.X--11.X.X" >&2
        echo "Please, don't put the resulting binaries into Chromium SVN" >&2
        build_valgrind "local"
      fi
      ;;
    "Darwin x86_64")
      if system_is_lion
      then
        build_valgrind "mac_10.7"
      elif system_is_snow_leopard
      then
        build_valgrind "mac_10.6" "--build=amd64-darwin"
      else
        echo "You have Darwin kernel different from 11.X.X" >&2
        echo "Please, don't put the resulting binaries into Chromium SVN" >&2
        build_valgrind "local"
      fi
      ;;
    *)
      build_valgrind "local"
      ;;
  esac
}

# Check that the binaries directory exists.
BINARIES_DIR="$THISDIR/../binaries"
if ! [ -a "$BINARIES_DIR" ]
then
  echo "Error: $BINARIES_DIR doesn't exist!" >&2
  exit 1
fi

set -e
set -x
